/**
 *  TextMash - simple IDE for Clojure
 *  
 *  Copyright (C) 2010 Aleksander Naszko
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package pl.olek.textmash.matching;

import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.Document;

import pl.olek.textmash.workspace.TextEditor;

/**
 * 
 * @author anaszko
 *
 */
public class BracketMatcher {
	TextEditor textPane;
	CaretListener listener;

	public BracketMatcher(TextEditor pane) {
		this.textPane = pane;

		listener = new CaretListener() {

			@Override
			public void caretUpdate(CaretEvent e) {
				processBrackets(e.getDot());
			}
		};

	}

	private void processBrackets(int offset) {
		if (offset == -1) {
			textPane.setBrackets(null);
		} else {
			textPane.setBrackets(match(textPane
					.getStyledDocument(), offset));
		}
		textPane.repaint();
	}

	public void turnOff() {
		textPane.removeCaretListener(listener);
		processBrackets(-1);
	}

	public void turnOn() {
		textPane.addCaretListener(listener);
		processBrackets(textPane.getCaretPosition());
	}

	final static char[] paren = new char[] { '(', ')', '{', '}', '[', ']', '<',
			'>', };



	public static BracketMatchingResult match(Document doc, int offset) {
		try {
			offset -= 1;
			if (doc.getLength() < 2) {
				return null;
			}
			if (offset < 0) {
				return null;
			}
			char startWith = doc.getText(offset, 1).charAt(0);
			boolean closing = false;
			char endWith;
			for (int i = 0; i < paren.length; ++i) {
				if (paren[i] == startWith) {
					if (i % 2 == 1) {
						closing = true;
						endWith = paren[i / 2 * 2];
					} else {
						endWith = paren[i + 1];
					}
					String txt;
					int count = 1;
					if (closing) {
						txt = doc.getText(0, offset);
						int z = txt.length() - 1;
						for (; z >= 0; --z) {
							char c = txt.charAt(z);
							if (c == startWith) {
								count++;
							} else if (c == endWith) {
								--count;
							}
							if (count == 0) {
								int r = offset - (txt.length() - z);
								BracketMatchingResult res = new BracketMatchingResult();
								res.start = offset;
								res.end = r;
								res.cstart = startWith;
								res.cend = endWith;
								return res;
							}
						}
					} else {
						txt = doc.getText(offset + 1, doc.getLength()
								- (offset + 1));
						for (int z = 0; z < txt.length(); ++z) {
							char c = txt.charAt(z);
							if (c == startWith) {
								count++;
							} else if (c == endWith) {
								--count;
							}
							if (count == 0) {
								int r = offset + z + 1;
								BracketMatchingResult res = new BracketMatchingResult();
								res.start = offset;
								res.end = r;
								res.cstart = startWith;
								res.cend = endWith;
								return res;
							}
						}
					}
					return null;
				}
			}
			return null;
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

}
